home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 1.iso
/
toolbox
/
src
/
exampleCode
/
opengl
/
x+opengl
/
paperplane.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-11-11
|
12KB
|
368 lines
/* $Revision: 1.1 $ */
/*
* paperplane can be compiled to use a "single visual" for the entire window
* hierarchy and render OpenGL into a standard Motif drawing area widget:
*
* cc -o sv_paperplane paperplane.c -DnoGLwidget -lGL -lXm -lXt -lX11 -lm
*
* Or paperplane can be compiled to use the default visual for most of
* the window hierarchy but render OpenGL into a special "OpenGL widget":
*
* cc -o glw_paperplane paperplane.c -lGLw -lGL -lXm -lXt -lX11 -lm
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <math.h>
#include <Xm/MainW.h>
#include <Xm/RowColumn.h>
#include <Xm/PushB.h>
#include <Xm/ToggleB.h>
#include <Xm/CascadeB.h>
#include <Xm/Frame.h>
#ifdef noGLwidget
#include <Xm/DrawingA.h> /* Motif drawing area widget */
#else
/** NOTE: in IRIX 5.2, the OpenGL widget headers are mistakenly in **/
/** <GL/GLwDrawA.h> and <GL/GlwMDraw.h> respectively. Below are the **/
/** _official_ standard locations. **/
#ifndef __sgi
#ifdef noMotifGLwidget
#include <X11/GLw/GLwDrawA.h> /* STANDARD: pure Xt OpenGL drawing area widget */
#else
#include <X11/GLw/GLwMDrawA.h> /* STANDARD: Motif OpenGL drawing area widget */
#endif
#else
#ifdef noMotifGLwidget
#include <GL/GLwDrawA.h> /* IRIX 5.2: pure Xt OpenGL drawing area widget */
#else
#include <GL/GLwMDrawA.h> /* IRIX 5.2: Motif OpenGL drawing area widget */
#endif
#endif
#endif
#include <X11/keysym.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glx.h>
static int dblBuf[] = {
GLX_DOUBLEBUFFER, GLX_RGBA, GLX_DEPTH_SIZE, 16,
GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1,
None
};
static int *snglBuf = &dblBuf[1];
static String fallbackResources[] = {
#ifdef IRIX_5_2_or_higher
"*sgiMode: true", /* try to enable IRIX 5.2+ look & feel */
"*useSchemes: all", /* and SGI schemes */
#endif
"*title: OpenGL paper plane demo",
"*glxarea*width: 300", "*glxarea*height: 300", NULL
};
Display *dpy;
GLboolean doubleBuffer = GL_TRUE, moving = GL_FALSE, made_current = GL_FALSE;
XtAppContext app;
XtWorkProcId workId = 0;
Widget toplevel, mainw, menubar, menupane, btn, cascade, frame, glxarea;
GLXContext cx;
XVisualInfo *vi;
#ifdef noGLwidget
Colormap cmap;
#endif
Arg menuPaneArgs[1], args[1];
#define MAX_PLANES 15
struct {
float speed; /* zero speed means not flying */
GLfloat red, green, blue;
float theta;
float x, y, z, angle;
} planes[MAX_PLANES];
#define v3f glVertex3f /* v3f was the short IRIS GL name for glVertex3f */
void draw(Widget w)
{
GLfloat red, green, blue;
int i;
glClear(GL_DEPTH_BUFFER_BIT);
/* paint black to blue smooth shaded polygon for background */
glDisable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
glBegin(GL_POLYGON);
glColor3f(0.0, 0.0, 0.0);
v3f(-20, 20, -19); v3f(20, 20, -19);
glColor3f(0.0, 0.0, 1.0);
v3f(20, -20, -19); v3f(-20, -20, -19);
glEnd();
/* paint planes */
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_FLAT);
for (i = 0; i < MAX_PLANES; i++)
if (planes[i].speed != 0.0) {
glPushMatrix();
glTranslatef(planes[i].x, planes[i].y, planes[i].z);
glRotatef(290.0, 1.0, 0.0, 0.0);
glRotatef(planes[i].angle, 0.0, 0.0, 1.0);
glScalef(1.0 / 3.0, 1.0 / 4.0, 1.0 / 4.0);
glTranslatef(0.0, -4.0, -1.5);
glBegin(GL_TRIANGLE_STRIP);
/* left wing */
v3f(-7.0, 0.0, 2.0); v3f(-1.0, 0.0, 3.0);
glColor3f(red = planes[i].red, green = planes[i].green,
blue = planes[i].blue);
v3f(-1.0, 7.0, 3.0);
/* left side */
glColor3f(0.6 * red, 0.6 * green, 0.6 * blue);
v3f(0.0, 0.0, 0.0); v3f(0.0, 8.0, 0.0);
/* right side */
v3f(1.0, 0.0, 3.0); v3f(1.0, 7.0, 3.0);
/* final tip of right wing */
glColor3f(red, green, blue);
v3f(7.0, 0.0, 2.0);
glEnd();
glPopMatrix();
}
if (doubleBuffer) glXSwapBuffers(dpy, XtWindow(w));
if(!glXIsDirect(dpy, cx))
glFinish(); /* avoid indirect rendering latency from queuing */
#ifdef DEBUG
{ /* for help debugging, report any OpenGL errors that occur per frame */
GLenum error;
while((error = glGetError()) != GL_NO_ERROR)
fprintf(stderr, "GL error: %s\n", gluErrorString(error));
}
#endif
}
void tick_per_plane(int i)
{
float theta = planes[i].theta += planes[i].speed;
planes[i].z = -9 + 4 * cos(theta);
planes[i].x = 4 * sin(2 * theta);
planes[i].y = sin(theta / 3.4) * 3;
planes[i].angle = ((atan(2.0) + M_PI_2) * sin(theta) - M_PI_2) * 180 / M_PI;
if (planes[i].speed < 0.0) planes[i].angle += 180;
}
void add_plane(void)
{
int i;
for (i = 0; i < MAX_PLANES; i++)
if (planes[i].speed == 0) {
#define SET_COLOR(r,g,b) \
planes[i].red=r; planes[i].green=g; planes[i].blue=b; break;
switch (random() % 6) {
case 0: SET_COLOR(1.0, 0.0, 0.0); /* red */
case 1: SET_COLOR(1.0, 1.0, 1.0); /* white */
case 2: SET_COLOR(0.0, 1.0, 0.0); /* green */
case 3: SET_COLOR(1.0, 0.0, 1.0); /* magenta */
case 4: SET_COLOR(1.0, 1.0, 0.0); /* yellow */
case 5: SET_COLOR(0.0, 1.0, 1.0); /* cyan */
}
planes[i].speed = (random() % 20) * 0.001 + 0.02;
if (random() & 0x1) planes[i].speed *= -1;
planes[i].theta = ((float) (random() % 257)) * 0.1111;
tick_per_plane(i);
if (!moving) draw(glxarea);
return;
}
XBell(dpy, 100); /* can't add any more planes */
}
void remove_plane(void)
{
int i;
for (i = MAX_PLANES - 1; i >= 0; i--)
if (planes[i].speed != 0) {
planes[i].speed = 0;
if (!moving) draw(glxarea);
return;
}
XBell(dpy, 100); /* no more planes to remove */
}
void resize(Widget w, XtPointer data, XtPointer callData)
{
Dimension width, height;
if(made_current) {
XtVaGetValues(w, XmNwidth, &width, XmNheight, &height, NULL);
glViewport(0, 0, (GLint) width, (GLint) height);
}
}
void tick(void)
{
int i;
for (i = 0; i < MAX_PLANES; i++)
if (planes[i].speed != 0.0) tick_per_plane(i);
}
Boolean animate(XtPointer data)
{
tick();
draw(glxarea);
return False; /* leave work proc active */
}
void toggle(void)
{
moving = !moving; /* toggle */
if (moving)
workId = XtAppAddWorkProc(app, animate, NULL);
else
XtRemoveWorkProc(workId);
}
void quit(Widget w, XtPointer data, XtPointer callData)
{
exit(0);
}
void input(Widget w, XtPointer data, XtPointer callData)
{
XmDrawingAreaCallbackStruct *cd = (XmDrawingAreaCallbackStruct *) callData;
char buf[1];
KeySym keysym;
int rc;
if(cd->event->type == KeyPress)
if(XLookupString((XKeyEvent *) cd->event, buf, 1, &keysym, NULL) == 1)
switch (keysym) {
case XK_space:
if (!moving) { /* advance one frame if not in motion */
tick();
draw(w);
}
break;
case XK_Escape:
exit(0);
}
}
void map_state_changed(Widget w, XtPointer data, XEvent * event, Boolean * cont)
{
switch (event->type) {
case MapNotify:
if (moving && workId != 0) workId = XtAppAddWorkProc(app, animate, NULL);
break;
case UnmapNotify:
if (moving) XtRemoveWorkProc(workId);
break;
}
}
main(int argc, char *argv[])
{
toplevel = XtAppInitialize(&app, "Paperplane", NULL, 0, &argc, argv,
fallbackResources, NULL, 0);
dpy = XtDisplay(toplevel);
/* find an OpenGL-capable RGB visual with depth buffer */
vi = glXChooseVisual(dpy, DefaultScreen(dpy), dblBuf);
if (vi == NULL) {
vi = glXChooseVisual(dpy, DefaultScreen(dpy), snglBuf);
if (vi == NULL)
XtAppError(app, "no RGB visual with depth buffer");
doubleBuffer = GL_FALSE;
}
/* create an OpenGL rendering context */
cx = glXCreateContext(dpy, vi, /* no display list sharing */ None,
/* favor direct */ GL_TRUE);
if (cx == NULL)
XtAppError(app, "could not create rendering context");
/* create an X colormap since probably not using default visual */
#ifdef noGLwidget
cmap = XCreateColormap(dpy, RootWindow(dpy, vi->screen),
vi->visual, AllocNone);
/*
* Establish the visual, depth, and colormap of the toplevel
* widget _before_ the widget is realized.
*/
XtVaSetValues(toplevel, XtNvisual, vi->visual, XtNdepth, vi->depth,
XtNcolormap, cmap, NULL);
#endif
XtAddEventHandler(toplevel, StructureNotifyMask, False,
map_state_changed, NULL);
mainw = XmCreateMainWindow(toplevel, "mainw", NULL, 0);
XtManageChild(mainw);
/* create menu bar */
menubar = XmCreateMenuBar(mainw, "menubar", NULL, 0);
XtManageChild(menubar);
#ifdef noGLwidget
/* Hack around Xt's unfortunate default visual inheritance. */
XtSetArg(menuPaneArgs[0], XmNvisual, vi->visual);
menupane = XmCreatePulldownMenu(menubar, "menupane", menuPaneArgs, 1);
#else
menupane = XmCreatePulldownMenu(menubar, "menupane", NULL, 0);
#endif
btn = XmCreatePushButton(menupane, "Quit", NULL, 0);
XtAddCallback(btn, XmNactivateCallback, quit, NULL);
XtManageChild(btn);
XtSetArg(args[0], XmNsubMenuId, menupane);
cascade = XmCreateCascadeButton(menubar, "File", args, 1);
XtManageChild(cascade);
#ifdef noGLwidget
menupane = XmCreatePulldownMenu(menubar, "menupane", menuPaneArgs, 1);
#else
menupane = XmCreatePulldownMenu(menubar, "menupane", NULL, 0);
#endif
btn = XmCreateToggleButton(menupane, "Motion", NULL, 0);
XtAddCallback(btn, XmNvalueChangedCallback, (XtCallbackProc)toggle, NULL);
XtManageChild(btn);
btn = XmCreatePushButton(menupane, "Add plane", NULL, 0);
XtAddCallback(btn, XmNactivateCallback, (XtCallbackProc)add_plane, NULL);
XtManageChild(btn);
btn = XmCreatePushButton(menupane, "Remove plane", NULL, 0);
XtAddCallback(btn, XmNactivateCallback, (XtCallbackProc)remove_plane, NULL);
XtManageChild(btn);
XtSetArg(args[0], XmNsubMenuId, menupane);
cascade = XmCreateCascadeButton(menubar, "Planes", args, 1);
XtManageChild(cascade);
/* create framed drawing area for OpenGL rendering */
frame = XmCreateFrame(mainw, "frame", NULL, 0);
XtManageChild(frame);
#ifdef noGLwidget
glxarea = XtVaCreateManagedWidget("glxarea", xmDrawingAreaWidgetClass,
frame, NULL);
#else
#ifdef noMotifGLwidget
/* notice glwDrawingAreaWidgetClass lacks an 'M' */
glxarea = XtVaCreateManagedWidget("glxarea", glwDrawingAreaWidgetClass,
#else
glxarea = XtVaCreateManagedWidget("glxarea", glwMDrawingAreaWidgetClass,
#endif
frame, GLwNvisualInfo, vi, NULL);
#endif
XtAddCallback(glxarea, XmNexposeCallback, (XtCallbackProc)draw, NULL);
XtAddCallback(glxarea, XmNresizeCallback, resize, NULL);
XtAddCallback(glxarea, XmNinputCallback, input, NULL);
/* set up application's window layout */
XmMainWindowSetAreas(mainw, menubar, NULL, NULL, NULL, frame);
XtRealizeWidget(toplevel);
/*
* Once widget is realized (ie, associated with a created X window), we
* can bind the OpenGL rendering context to the window.
*/
glXMakeCurrent(dpy, XtWindow(glxarea), cx);
made_current = GL_TRUE;
/* setup OpenGL state */
glClearDepth(1.0);
glClearColor(0.0, 0.0, 0.0, 0.0);
glMatrixMode(GL_PROJECTION);
glFrustum(-1.0, 1.0, -1.0, 1.0, 1.0, 20);
glMatrixMode(GL_MODELVIEW);
/* add three initial random planes */
srandom(getpid());
add_plane(); add_plane(); add_plane();
/* start event processing */
XtAppMainLoop(app);
}